package math.statistics.distribution;

/**
 * A class for doing simple numerical analysis on discrete random variables.
 *
 * Fully Tested: No
 * Fully Documented: Yes
 * Created: Nov-2011
 * Last Updated: 13-Dec-2011
 * 
 * @author Shimu
 */
public class DiscreteProbabilityDistribution extends StatisticalDistribution {

    /** 
     * The number of possible values of the discrete 
     * probability distribution 
     */
    private int size;

    private float[] x, probability;

    /**
     * Instantiates a DiscreteProbabilityDistribution given an array of
     * possible values the random variable can take on and an array of
     * probability values corresponding to the probability that each value
     * will occur.
     * 
     * @param x an array storing all the possible values that the discrete
     * random variable can take on
     * @param probabilityDistribution an array storing the probability 
     * distribution of the random variable, that is, the array stores the
     * probability of each value occurring
     * 
     * @throws ProbabilityException if the given x and the given 
     * probabilityDistribution array do not have the same length
     */
    public DiscreteProbabilityDistribution(float[] x,
            float[] probabilityDistribution)
            throws ProbabilityException {
        if (x.length != probabilityDistribution.length) {
            throw new ProbabilityException("The length of array x is not the"
                    + " same as the length of array probability!");
        }
        this.size = x.length;
        this.x = x;
        this.probability = probabilityDistribution;
        this.mean = null;
        this.standardDeviation = null;
    }

    /**
     * <p>Returns the mean of this probability distribution. The mean is
     * calculated as the weighted sum of all the x values.</p>
     * <p> mean = Σ x<sub>i</sub>p<sub>i</sub> </p>
     * <p> where x<sub>i</sub> is a value the random variable can take on and
     * p<sub>i</sub> is the probability of that value occurring </p>
     * 
     * @return the mean of this probability distribution.
     */
    public double getMean() {
        if (mean == null) {
            mean = 0.0;
            for (int i = 0; i < size; i++) {
                mean += x[i] * probability[i];
            }
        }
        return mean;
    }

    /**
     * <p> Returns the standard deviation of this probability distribution. The
     * standard deviation is calculated as the weighted square deviation
     * from the mean. </p>
     * 
     * <p> standard deviation = Σ (x<sub>i</sub> - mean)<sup>2</sup>
     * p<sub>i</sub>
     * 
     * @return the standard deviation of this probability distribution.
     */
    public double getStandardDeviation() {
        if (standardDeviation == null) {
            getMean();
            double variance = 0.0;
            for (int i = 0; i < size; i++) {
                variance += (Math.pow(x[i] - mean, 2))
                        * probability[i];
            }
            standardDeviation = Math.sqrt(variance);
        }
        return standardDeviation;
    }
}
